<html>
<head><meta charset="utf-8"><title>Separate length function for arrays · t-libs · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/index.html">t-libs</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html">Separate length function for arrays</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="243058148"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243058148" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243058148">(Jun 17 2021 at 17:59)</a>:</h4>
<p>I’ve made a PR that adds a separate length function for arrays that is useful for MIR and (locally without unstable flags) it just works. There is a PR, so is it possible to make it insta-stable and run a crater over it? <a href="https://github.com/rust-lang/rust/pull/86404">https://github.com/rust-lang/rust/pull/86404</a></p>



<a name="243060268"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243060268" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243060268">(Jun 17 2021 at 18:13)</a>:</h4>
<p>Potentially-terrible idea: Things like <code>+</code> on primitives and <code>[0]</code> on arrays/slices are magically lowered to the MIR operations, rather than to the corresponding trait methods calls.  Could it make sense to treat <code>.len()</code> like that too?</p>
<p>(Seems like that could be net easier than having the call in MIR, then inlining it sometimes and MIR-opt'ing it away in the other cases...)</p>



<a name="243066567"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243066567" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243066567">(Jun 17 2021 at 18:56)</a>:</h4>
<p>hm, we already have this for Vec::len and Vec::is_empty (even though they're also available through deref to []) and a few others. and i don't think that was ever a problem</p>



<a name="243066676"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243066676" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243066676">(Jun 17 2021 at 18:57)</a>:</h4>
<p><span class="user-mention" data-user-id="420832">@Alex Vlasov</span> the PR just says "solve #..", but that just links to the tracking issue you opened for the PR. is there an issue that describes the problem this is solving?</p>



<a name="243067135"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243067135" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243067135">(Jun 17 2021 at 19:01)</a>:</h4>
<p>There is nothing else, but I’ve made a short description that basically separate functions allows MIR to propagate constants there without any extra modifications</p>



<a name="243067346"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243067346" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243067346">(Jun 17 2021 at 19:02)</a>:</h4>
<p>but it doesn't explain why that doesn't already happen before this change, and why it is a problem that it doesn't happen.</p>
<p>and i'd expect some discussion about why this isn't better solved on the side of MIR first</p>



<a name="243067693"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243067693" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243067693">(Jun 17 2021 at 19:05)</a>:</h4>
<p>I’ve solved lowering slice::len in the MIR Len operation in a separate PR, but for this one I either have to do a similar thing (and more complicated actually), or just update the core. The underlying reason is that array length actually calls slice::len that does some pointer magic and looks not transparent enough for the correct constant propagation</p>



<a name="243067934"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243067934" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243067934">(Jun 17 2021 at 19:06)</a>:</h4>
<p>it just accesses a union though? const eval can handle that</p>



<a name="243068008"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243068008" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243068008">(Jun 17 2021 at 19:07)</a>:</h4>
<p>we can't really review this without all the context. do you have links to what you changed in MIR, and to any discussion about why this would have to be solved in the library rather than in mir?</p>



<a name="243068447"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243068447" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243068447">(Jun 17 2021 at 19:10)</a>:</h4>
<p>Main reason is kind of “why not”? Insta-stable method allows to express it on a library level without modifications into the compiler. Even I’m not sure that I’ve observed all the edge cases for it, but can spam more mir optimization tests</p>



<a name="243068679"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243068679" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243068679">(Jun 17 2021 at 19:11)</a>:</h4>
<p>express what exactly? what does it solve?</p>



<a name="243069759"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243069759" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243069759">(Jun 17 2021 at 19:18)</a>:</h4>
<p>I've made a simple MIR optimization test for a code like</p>
<div class="codehilite"><pre><span></span><code>// EMIT_MIR lower_slice_len.array_bound.SimplifyLocals.diff
pub fn array_bound&lt;const N: usize&gt;(index: usize, slice: &amp;[u8; N]) -&gt; u8 {
    if index &lt; slice.len() {
        slice[index]
    } else {
        42
    }
}
</code></pre></div>
<p>(hacking into SimplifyLocals as the last pass for simplicity, so after any constant prop, mir-opt-level = 3)</p>
<p>here is a MIR</p>
<div class="codehilite"><pre><span></span><code>- // MIR for `array_bound` before SimplifyLocals
+ // MIR for `array_bound` after SimplifyLocals

  fn array_bound(_1: usize, _2: &amp;[u8; N]) -&gt; u8 {
      debug index =&gt; _1;                   // in scope 0 at $DIR/lower_slice_len.rs:14:36: 14:41
      debug slice =&gt; _2;                   // in scope 0 at $DIR/lower_slice_len.rs:14:50: 14:55
      let mut _0: u8;                      // return place in scope 0 at $DIR/lower_slice_len.rs:14:70: 14:72
      let mut _3: bool;                    // in scope 0 at $DIR/lower_slice_len.rs:15:8: 15:27
      let mut _4: usize;                   // in scope 0 at $DIR/lower_slice_len.rs:15:8: 15:13
      let mut _5: usize;                   // in scope 0 at $DIR/lower_slice_len.rs:15:16: 15:27
      let mut _6: &amp;[u8];                   // in scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
      let mut _7: &amp;[u8; N];                // in scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
      let _8: usize;                       // in scope 0 at $DIR/lower_slice_len.rs:16:15: 16:20
      let mut _9: usize;                   // in scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21
      let mut _10: bool;                   // in scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21

      bb0: {
          StorageLive(_3);                 // scope 0 at $DIR/lower_slice_len.rs:15:8: 15:27
          StorageLive(_4);                 // scope 0 at $DIR/lower_slice_len.rs:15:8: 15:13
          _4 = _1;                         // scope 0 at $DIR/lower_slice_len.rs:15:8: 15:13
          StorageLive(_5);                 // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:27
          StorageLive(_6);                 // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
          StorageLive(_7);                 // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
          _7 = _2;                         // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
          _6 = move _7 as &amp;[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:21
          StorageDead(_7);                 // scope 0 at $DIR/lower_slice_len.rs:15:20: 15:21
          _5 = Len((*_6));                 // scope 0 at $DIR/lower_slice_len.rs:15:16: 15:27
          StorageDead(_6);                 // scope 0 at $DIR/lower_slice_len.rs:15:26: 15:27
          _3 = Lt(move _4, move _5);       // scope 0 at $DIR/lower_slice_len.rs:15:8: 15:27
          StorageDead(_5);                 // scope 0 at $DIR/lower_slice_len.rs:15:26: 15:27
          StorageDead(_4);                 // scope 0 at $DIR/lower_slice_len.rs:15:26: 15:27
          switchInt(move _3) -&gt; [false: bb2, otherwise: bb1]; // scope 0 at $DIR/lower_slice_len.rs:15:5: 19:6
      }

      bb1: {
          StorageLive(_8);                 // scope 0 at $DIR/lower_slice_len.rs:16:15: 16:20
          _8 = _1;                         // scope 0 at $DIR/lower_slice_len.rs:16:15: 16:20
          _9 = const N;                    // scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21
          _10 = Lt(_8, _9);                // scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21
          assert(move _10, &quot;index out of bounds: the length is {} but the index is {}&quot;, move _9, _8) -&gt; bb3; // scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21
      }

      bb2: {
          _0 = const 42_u8;                // scope 0 at $DIR/lower_slice_len.rs:18:9: 18:11
          goto -&gt; bb4;                     // scope 0 at $DIR/lower_slice_len.rs:15:5: 19:6
      }

      bb3: {
          _0 = (*_2)[_8];                  // scope 0 at $DIR/lower_slice_len.rs:16:9: 16:21
          StorageDead(_8);                 // scope 0 at $DIR/lower_slice_len.rs:17:5: 17:6
          goto -&gt; bb4;                     // scope 0 at $DIR/lower_slice_len.rs:15:5: 19:6
      }

      bb4: {
          StorageDead(_3);                 // scope 0 at $DIR/lower_slice_len.rs:19:5: 19:6
          return;                          // scope 0 at $DIR/lower_slice_len.rs:20:2: 20:2
      }
  }
</code></pre></div>
<p>If I make a library modification then <code>_5 = Len((*_6));</code> becomes <code>_5 = N;</code></p>



<a name="243070067"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243070067" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243070067">(Jun 17 2021 at 19:21)</a>:</h4>
<p>In bound checks <code>_9 = const N;</code> is fine as expected, but not in the user code</p>



<a name="243070439"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243070439" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243070439">(Jun 17 2021 at 19:23)</a>:</h4>
<p>Note that if MIR's <code>Len</code> is called on an array, then instcombine will lower it to the constant: <a href="https://github.com/rust-lang/rust/blob/master/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff#L33">https://github.com/rust-lang/rust/blob/master/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff#L33</a></p>
<p>So in-bounds array indexing already removes the check: <a href="https://rust.godbolt.org/z/r7bhaxWG4">https://rust.godbolt.org/z/r7bhaxWG4</a></p>



<a name="243070945"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243070945" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243070945">(Jun 17 2021 at 19:27)</a>:</h4>
<p>Here <code>Len</code> is not called on the array and instead it's called on <code>move _7 as &amp;[u8] (Pointer(Unsize));</code>. So this coercion will be eliminated</p>



<a name="243071096"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243071096" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243071096">(Jun 17 2021 at 19:28)</a>:</h4>
<p>Actually <code>Len</code> is not even called there, it's a result of <a href="https://github.com/rust-lang/rust/pull/86383">https://github.com/rust-lang/rust/pull/86383</a> that I already use in my work</p>



<a name="243071158"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243071158" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243071158">(Jun 17 2021 at 19:28)</a>:</h4>
<p>Before such PR it would call <code>core::slice::&lt;impl [u8]&gt;::len</code> there</p>



<a name="243302736"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243302736" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243302736">(Jun 20 2021 at 13:19)</a>:</h4>
<p>I've marked a function as insta-const-stable (well, to the best of my guess how it should be marked), tests pass locally, so it may be interesting to run CI, performance and crater</p>



<a name="243309140"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243309140" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243309140">(Jun 20 2021 at 16:02)</a>:</h4>
<p>hm, I understand why this has to be insta-stable, but does it have to be insta-const stable? I thought the const stability checker was capable enough to do that</p>



<a name="243363963"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243363963" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243363963">(Jun 21 2021 at 10:35)</a>:</h4>
<p>A function like this </p>
<div class="codehilite"><pre><span></span><code>pub const fn length&lt;const N: usize&gt;(_arr: &amp;[u8; N]) -&gt; usize {
    N
}
</code></pre></div>
<p>is already accepted by 1.52 stable, so it's ok to have an explicit <code>const</code> marker</p>



<a name="243380715"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243380715" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243380715">(Jun 21 2021 at 13:22)</a>:</h4>
<p>slice::len is already const</p>



<a name="243388950"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243388950" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243388950">(Jun 21 2021 at 14:19)</a>:</h4>
<p>Ok, so it actually has to be const then. In any case CI doesn’t show any problems, so can it be considered for merging (modulo my noobie insta-const-stable attempt)?</p>



<a name="243390231"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390231" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390231">(Jun 21 2021 at 14:28)</a>:</h4>
<p>insta-const is fine</p>



<a name="243390274"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390274" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390274">(Jun 21 2021 at 14:28)</a>:</h4>
<p>a new function can be immediately stabilized as const with its own stabilization</p>



<a name="243390407"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390407" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390407">(Jun 21 2021 at 14:29)</a>:</h4>
<p>i'm not really convinced yet we need this function at all</p>



<a name="243390555"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390555" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390555">(Jun 21 2021 at 14:30)</a>:</h4>
<p>it'd be a bit of a weird function, because it takes &amp;self and doesn't use it at all. the length info is already statically known.</p>



<a name="243390558"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390558" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390558">(Jun 21 2021 at 14:30)</a>:</h4>
<p>I'm just here for the "const" part, the other part is not my department <span aria-label="tm" class="emoji emoji-2122" role="img" title="tm">:tm:</span></p>



<a name="243390590"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243390590" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243390590">(Jun 21 2021 at 14:30)</a>:</h4>
<p>^^</p>



<a name="243391451"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243391451" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243391451">(Jun 21 2021 at 14:35)</a>:</h4>
<p>but now that I think on it... I still have opinions. Its only motivation is making MIR opts simpler as far as I can tell. But that only helps arrays. We could instead go the mir opt route and figure out what the minimal opt improvement is that makes it work out. Probably just making const prop handle the runtime array to slice op to create a (runtime, constant array length) pair (for the wide pointer that is used after the unsizing to slice) instead of bailing out "because runtime"</p>



<a name="243391469"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243391469" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243391469">(Jun 21 2021 at 14:35)</a>:</h4>
<p>The example of “why it’s needed is above”. Yes, it’s artificial in a sense that it’s only type information related function and doesn’t care about &amp;self, but it’s intuitive for users in a sense of syntax and signature, allows better MIR already, and may be handy when full const genetics and const machinery will hit</p>



<a name="243391852"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243391852" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243391852">(Jun 21 2021 at 14:38)</a>:</h4>
<p>but this should be handled on the mir side, right? as oli is saying.</p>



<a name="243393292"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243393292" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243393292">(Jun 21 2021 at 14:47)</a>:</h4>
<p>Even though I’ve built a similar MIR pass for slice length I would want to avoid this pass as then all the structures that potentially coerce into slices may require such pass  </p>
<p>Separately I’d say slice and array  length should be an intrinsic - then already have a special MIR op called Len, so it would be a easier to maintain if we take such artillery as additional niche optimization pass</p>



<a name="243393495"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243393495" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243393495">(Jun 21 2021 at 14:49)</a>:</h4>
<p>I’ve started all these to be able to make MIR pass that provably eliminates bound checks without LLVM, but in a worst case I can make few more required niches</p>



<a name="243394305"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243394305" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243394305">(Jun 21 2021 at 14:54)</a>:</h4>
<p>what I'm trying to say is that this is something we want to do in const prop <em>anyway</em>. If doing it in const prop makes the other methods irrelevant, then it would be my preference to only do it there</p>



<a name="243394842"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243394842" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243394842">(Jun 21 2021 at 14:57)</a>:</h4>
<p>Const prop will do it already if something like _2 = _1 as &amp;[T]; Len(* _2) will be patched to just Len(* _1)</p>



<a name="243397319"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243397319" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243397319">(Jun 21 2021 at 15:12)</a>:</h4>
<p>Can we then consider an idea of length intrinsic then that it easier to maintain then niche MIR patches?</p>



<a name="243397455"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243397455" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243397455">(Jun 21 2021 at 15:13)</a>:</h4>
<p>It would still require a separate function though</p>



<a name="243398497"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243398497" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Lokathor <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243398497">(Jun 21 2021 at 15:21)</a>:</h4>
<p><span class="user-mention silent" data-user-id="310399">Mara</span> <a href="#narrow/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays/near/243390555">said</a>:</p>
<blockquote>
<p>it'd be a bit of a weird function, because it takes &amp;self and doesn't use it at all. the length info is already statically known.</p>
</blockquote>
<p>If this is a concern, perhaps rationalize it like this: The function doesn't needs <code>&amp;self</code>, however to make it use method syntax then some sort of self argument must be present. From there, to play the most nicely with the borrow/ownership of Rust, we pick <code>&amp;self</code>, because it is the least intrusive to whatever else the programmer is doing before and after they call this method.</p>



<a name="243398647"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243398647" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mara <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243398647">(Jun 21 2021 at 15:22)</a>:</h4>
<p>i'm just saying that we already have a slice::len. and in contexts where it matters that it's an array, you already have the length N around. and regardless, this seems like a mir-opt thing instead of a library thing.</p>



<a name="243400121"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243400121" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243400121">(Jun 21 2021 at 15:32)</a>:</h4>
<p>could be lightly precedented by <code>mem::size_of_val</code>, which takes a <code>&amp;T</code> parameter just to look up metadata about the type. but it would be nice if this could just be a guaranteed optimization, yes</p>



<a name="243401015"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243401015" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243401015">(Jun 21 2021 at 15:38)</a>:</h4>
<p>if you wanted to better express that this is a statically-known property of the type you could have <code>impl [T; N] { const LEN: usize = N }</code>, but of course that's not the exact same API</p>



<a name="243401124"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243401124" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243401124">(Jun 21 2021 at 15:38)</a>:</h4>
<p>We also already have a Vec::len, that doesn’t go into slice coercion and fast tracks to specific implementation</p>



<a name="243401634"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243401634" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243401634">(Jun 21 2021 at 15:40)</a>:</h4>
<p>In any case at the end of the day any sane code from may be even users who are a little lazy should become _1 = const N in MIR, this is a fastest option, other ones require more code</p>



<a name="243402150"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243402150" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243402150">(Jun 21 2021 at 15:44)</a>:</h4>
<p>In case of <code>size_of_val</code> the size may be looked up/calculated from the reference metadata if it is a fat pointer.</p>



<a name="243409138"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243409138" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243409138">(Jun 21 2021 at 16:39)</a>:</h4>
<p>I think I'm with oli and Mara on this one FWIW.  If MIR was SSA it'd be easy to see "unsize+len" and fold that down to the length.  So it seems weird to add a library function just because it's hard to write optimizations in MIR.</p>



<a name="243411600"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243411600" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243411600">(Jun 21 2021 at 16:59)</a>:</h4>
<p>It’s not “hard”, but MIR pass is a global performance hit (small, but still), and library function is less invasive</p>



<a name="243415652"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243415652" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243415652">(Jun 21 2021 at 17:30)</a>:</h4>
<p>I dunno, the library function is so invasive that it requires signoff from an entirely different team</p>



<a name="243427387"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243427387" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243427387">(Jun 21 2021 at 18:58)</a>:</h4>
<p><span class="user-mention silent" data-user-id="420832">Alex Vlasov</span> <a href="#narrow/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays/near/243411600">said</a>:</p>
<blockquote>
<p>It’s not “hard”, but MIR pass is a global performance hit (small, but still), and library function is less invasive</p>
</blockquote>
<p>we will get this hit anyway when we generalize const prop to handle such unsizing ops</p>



<a name="243440616"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243440616" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Wesley Wiser <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243440616">(Jun 21 2021 at 20:47)</a>:</h4>
<p>I also think this should be solved at the MIR level and not by adding a new library function.</p>



<a name="243449190"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243449190" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Lokathor <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243449190">(Jun 21 2021 at 22:04)</a>:</h4>
<p><span class="user-mention silent" data-user-id="211727">Jonas Schievink  [he/him]</span> <a href="#narrow/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays/near/243415652">said</a>:</p>
<blockquote>
<p>I dunno, the library function is so invasive that it requires signoff from an entirely different team</p>
</blockquote>
<p>libs-api has to sign off on all new api, regardless of invasiveness level, so them having to sign off on the new api doesn't indicate in any way how invasive or not the new method is.</p>



<a name="243450529"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243450529" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243450529">(Jun 21 2021 at 22:19)</a>:</h4>
<p>I've made a draft of the pass and it's not pretty to be both simple and sound. Further MIR passes will optimize away the leftovers, but it requires creation of the intermediate local,  making live, extra copy, patching <code>Len</code> and making local dead</p>



<a name="243450543"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243450543" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243450543">(Jun 21 2021 at 22:19)</a>:</h4>
<p><a href="https://github.com/rust-lang/rust/pull/86525">https://github.com/rust-lang/rust/pull/86525</a></p>



<a name="243483752"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243483752" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243483752">(Jun 22 2021 at 08:06)</a>:</h4>
<p>Sorry, I have been severly unhelpful, just throwing out statements without explanation. I got a few minutes, so here hopefully goes something coherent: I don't think we should have a new pass. Instead we should teach const prop to handle a) unsizing casts, even from runtime values, as that will give us a partial constant wide pointer, where the pointer part is unknown, but the length part is constant, and b) Len to work on slices, by checking whether the length is constant and completely ignoring the actual pointer part. These two steps can both be done in <a href="https://github.com/rust-lang/rust/pull/86525/files#diff-4b547ad83c74d17a147c275e70e658b432d5080cbcdb25aa800989d4affb6a70">https://github.com/rust-lang/rust/pull/86525/files#diff-4b547ad83c74d17a147c275e70e658b432d5080cbcdb25aa800989d4affb6a70</a>, by adding an arm for the Cast rvalue. The Cast rvalue should specifically check for unsizing casts, while the Len rvalue probably doesn't even need an impl, we can just go the default route which should only touch the length. If not, we'll also need a special handler for the Len rvalue. Since we are now producing a previously unknown thing (namely a "tuple" (wide pointer) where part of it is undefined, we also need to adjust <a href="https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir/src/transform/const_prop.rs#L928-L931">https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir/src/transform/const_prop.rs#L928-L931</a> to be able to support ScalarMaybeUninit::Undef.</p>
<p>Does this make sense? Am I misunderstanding what the MIR at the const prop level is and this isn't possible the way I'm thinking?</p>



<a name="243488043"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243488043" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243488043">(Jun 22 2021 at 08:53)</a>:</h4>
<p>I think it's an option, but can you also explain relation (or desired relation) between such MIR hacks and potentially full CTFE that should be able to make the same conclusions and (later on when slice.len() is const) propagate the constants in a consistent way?</p>



<a name="243489984"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243489984" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243489984">(Jun 22 2021 at 09:14)</a>:</h4>
<p>Hmm... good point, maybe we don't need to do the steps in the first link at all. It may already all be working correctly due to the CTFE machinery. This needs to be debugged, but potentially you can just do the thing at the second link, allowing partially undef scalar pairs</p>



<a name="243490036"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243490036" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243490036">(Jun 22 2021 at 09:15)</a>:</h4>
<blockquote>
<p>make the same conclusions and (later on when slice.len() is const) propagate the constants in a consistent way?</p>
</blockquote>
<p>I don't understand what you mean by this part</p>



<a name="243493647"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243493647" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243493647">(Jun 22 2021 at 09:52)</a>:</h4>
<p>My impression was that CTFE is separate (CTFE allows to e.g. evaluate <code>slice.len()</code> in it's current form before <a href="https://github.com/rust-lang/rust/pull/86383#issuecomment-862749123">https://github.com/rust-lang/rust/pull/86383#issuecomment-862749123</a> changed it, or any other <code>const</code> function) and MIR transformations are separate - just walk over MIR and reorder how you want</p>



<a name="243499387"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243499387" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243499387">(Jun 22 2021 at 10:58)</a>:</h4>
<p>yes they are</p>



<a name="243499401"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243499401" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243499401">(Jun 22 2021 at 10:58)</a>:</h4>
<p>but I don't get how CTFE is relevant beyond sharing code with const prop</p>



<a name="243499748"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243499748" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243499748">(Jun 22 2021 at 11:02)</a>:</h4>
<p>const prop is a mir opt, and will run on any non-ctfe mir to ensure simple runtime constants are optimized away when used in operations</p>



<a name="243499820"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243499820" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243499820">(Jun 22 2021 at 11:02)</a>:</h4>
<p>so 1+1 becomes 2 in mir, without involving ctfe at all</p>



<a name="243499884"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243499884" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243499884">(Jun 22 2021 at 11:03)</a>:</h4>
<p>anything not constant is treated as undef in const prop</p>



<a name="243500036"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243500036" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243500036">(Jun 22 2021 at 11:04)</a>:</h4>
<p>so x + 1 is not propped, because the shared const machinery (miri engine) errors out if you add undef with anything</p>



<a name="243502102"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243502102" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243502102">(Jun 22 2021 at 11:26)</a>:</h4>
<p>Well, CTFE is relevant, because we have options:</p>
<ul>
<li>lib function, that is <code>const</code>, handled by const propagation without extra changes in MIR, and most likely trivial for CTFE, everything for one lib change</li>
<li>no lib function, but then it may potentially diverge modulo my knowledge. I don't know how CTFE works and what is it's input (MIR?). If it's MIR then sure, ConstProp patch is a way to go, but otherwise we can get a case when for <code>&amp;[T;N].len()</code> MIR will end up with having a code that effectively uses a const value, but CTFE will follow some other pass and may fail to compute <code>&amp;[T].len()</code> into constant, while it should</li>
</ul>



<a name="243503136"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243503136" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243503136">(Jun 22 2021 at 11:36)</a>:</h4>
<p>This possible divergence is true for all optimizations, but only if they are buggy. Optimizations do not affect CTFE, and optimizations that miscompile... should be fixed, that's a soundness bug after all. For this situation, all we're doing is moving an optimizations that LLVM does anyway, and putting it into MIR. So we don't actually change anything to the status quo, except that we get simpler MIR</p>



<a name="243503187"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243503187" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243503187">(Jun 22 2021 at 11:37)</a>:</h4>
<p>CTFE works on different MIR than LLVM uses for codegen. the MIR is cloned for CTFE and stored, before optimizations are run on MIR</p>



<a name="243503540"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243503540" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243503540">(Jun 22 2021 at 11:40)</a>:</h4>
<p>so yes, we could definitely diverge, but any divergence due to mir opts would be a soundness bug I presume. We are very careful with adding new const features, e.g. floating point math can be very different when optimized, const evaluated, or done at runtime. Since we use separate MIR for runtime and CTFE, the slice::len function which already works in CTFE on slices or arrays just fine, would not suddenly fail to compute said length, no matter how much we mangle the MIR in optimizations</p>



<a name="243504394"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243504394" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243504394">(Jun 22 2021 at 11:51)</a>:</h4>
<p>Yeah, that's tricky. Then CTFE has to be patched immediately to be able to see through array -&gt; slice casts in a similar manner</p>



<a name="243505864"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243505864" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243505864">(Jun 22 2021 at 12:07)</a>:</h4>
<p><span class="user-mention silent" data-user-id="420832">Alex Vlasov</span> <a href="#narrow/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays/near/243504394">said</a>:</p>
<blockquote>
<p>Yeah, that's tricky. Then CTFE has to be patched immediately to be able to see through array -&gt; slice casts in a similar manner</p>
</blockquote>
<p>it doesn't have to be patched, it already works in CTFE, and we aren't touching the MIR that CTFE uses</p>



<a name="243506215"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243506215" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243506215">(Jun 22 2021 at 12:10)</a>:</h4>
<p>Example showing how CTFE does this: <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=14b078f5732f994e6e76c6db1ef4d575">https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=14b078f5732f994e6e76c6db1ef4d575</a>. The MIR of the constant is</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="w">        </span><span class="n">_1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="k">const</span><span class="w"> </span><span class="mi">42_</span><span class="k">i32</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="mi">43_</span><span class="k">i32</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="mi">44_</span><span class="k">i32</span><span class="p">];</span><span class="w"> </span><span class="c1">// scope 0 at src/main.rs:2:13: 2:25</span>
<span class="w">        </span><span class="n">StorageLive</span><span class="p">(</span><span class="n">_2</span><span class="p">);</span><span class="w">                 </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:6</span>
<span class="w">        </span><span class="n">StorageLive</span><span class="p">(</span><span class="n">_3</span><span class="p">);</span><span class="w">                 </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:6</span>
<span class="w">        </span><span class="n">_3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">_1</span><span class="p">;</span><span class="w">                        </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:6</span>
<span class="w">        </span><span class="n">_2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="n">_3</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">&amp;</span><span class="p">[</span><span class="kt">i32</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="n">Pointer</span><span class="p">(</span><span class="n">Unsize</span><span class="p">));</span><span class="w"> </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:6</span>
<span class="w">        </span><span class="n">StorageDead</span><span class="p">(</span><span class="n">_3</span><span class="p">);</span><span class="w">                 </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:6</span>
<span class="w">        </span><span class="n">_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">core</span>::<span class="n">slice</span>::<span class="o">&lt;</span><span class="k">impl</span><span class="w"> </span><span class="p">[</span><span class="kt">i32</span><span class="p">]</span><span class="o">&gt;</span>::<span class="n">len</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="n">_2</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">bb1</span><span class="p">;</span><span class="w"> </span><span class="c1">// scope 1 at src/main.rs:3:5: 3:12</span>
</code></pre></div>
<p>so all steps work already</p>



<a name="243507434"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243507434" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243507434">(Jun 22 2021 at 12:23)</a>:</h4>
<p>Ok, let me try to get into ConstProp</p>



<a name="243514409"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243514409" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243514409">(Jun 22 2021 at 13:19)</a>:</h4>
<p>I'll try to find some time for your open PR. It's too complex for a casual review, and I'm still on leave until 5th of July, so I unfortunately can't promise anything until then. the mir diffs are looking nice tho</p>



<a name="243559296"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243559296" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243559296">(Jun 22 2021 at 18:28)</a>:</h4>
<p>From by brief understanding of const-prop I do not thing it can work. Yes, one can get a concrete value of array length like in the example above, but not the type system constant <code>N</code></p>



<a name="243611457"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243611457" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243611457">(Jun 23 2021 at 06:30)</a>:</h4>
<p>that's true. that is a general limitation of const prop</p>



<a name="243634253"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243634253" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243634253">(Jun 23 2021 at 10:51)</a>:</h4>
<p>Ok, so far the results:</p>
<ul>
<li><a href="https://github.com/rust-lang/rust/pull/86525">https://github.com/rust-lang/rust/pull/86525</a> achieves a propagation of _1 = const N at the cost of overhead of the optimization pass that for a heavy use of arrays with unremoved bound checks (my guess) leads to slowdowns (keccak example in performance run)</li>
<li>this library extension: get all the same for free (neutral in performance)</li>
</ul>
<p>May be this function is a good candidate for 2021 edition? At least consistent with array.into_iter()</p>



<a name="243669379"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243669379" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243669379">(Jun 23 2021 at 15:31)</a>:</h4>
<p>since the original concern over this addition was along the lines of "please elaborate why this isn't addressed in MIR instead" , and since that approach appears to require 300x more code and has significant perf implications, that seems to me to be a pretty good argument in favor of the inherent method</p>



<a name="243671622"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243671622" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Wesley Wiser <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243671622">(Jun 23 2021 at 15:47)</a>:</h4>
<p>In general, my opinion is that MIR optimizations should be transparent to users in that there should be no difference in program behavior or language or library behavior whether they are enabled or disabled. I believe they should also be pretty tightly encapsulated in the rustc_mir library and not affect various other parts of the compiler. </p>
<p>Having said that, if there was a very compelling reason to break those general principles, then that seems entirely reasonable to me. For example, if we can achieve a 20% throughput improvement in compiler performance but it requires touching lots of parts of the compiler, that seems like a worthwhile engineering trade-off to me.</p>
<p>In this case, even if we add the library function, which doesn't seem very useful to users in general to me, perf results show no real change in compiler performance. I would be very surprised if there was a change in code quality under the release profile as LLVM should be able to trivially optimize these cases itself. There could be an improvement to code quality in the debug profile but that has historically not been something we've cared a lot about. </p>
<p>Given that the usual justification for MIR optimizations (perf.rlo shows improvements) doesn't seem to currently apply, I think it would be helpful to elaborate more on what the desired end goal is here. That would help evaluate the tradeoff between more complex MIR opts and adding a library function.</p>



<a name="243681733"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243681733" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243681733">(Jun 23 2021 at 17:02)</a>:</h4>
<p>There is a message in the beginning of the thread that all those optimizations for length related MIR, etc are just a prelude for the main work, that is first static analysis to eliminate range checks, and then more generic range analysis. For this I’d prefer to start with MIR that is as homogeneous as possible, so I did 3 things:</p>
<ul>
<li>lower slice len call from function call to Len MIR operation (merged)</li>
<li>introduced this proposal to get lowering of array length into _1 = const N - type system constant. It can alternatively be done by the a little expensive MIR pass</li>
<li>introduced a pass that eliminated intermediate copies like _2 = _1; _3 = Op(move _2); StorageDead(_2)</li>
</ul>
<p>All those 3 are required for a good point to start eliminating bound checks</p>



<a name="243682159"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243682159" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243682159">(Jun 23 2021 at 17:05)</a>:</h4>
<p>So far the most reasonable objection I have see on the special .len() for arrays is that it doesn’t actually care about &amp;self, but when full const genetics kick in I believe other similar cases may emerge</p>



<a name="243682309"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243682309" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243682309">(Jun 23 2021 at 17:06)</a>:</h4>
<p>And for sure “neutral performance impact” and no failing tests is better than negative one</p>



<a name="243682479"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243682479" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243682479">(Jun 23 2021 at 17:08)</a>:</h4>
<p>It’s actually funny that even though there is a MIR pass “instcombine” that should lower Len() on arrays into the constant it can not work in practice if the operand is &amp;[T; N]</p>



<a name="243682952"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243682952" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243682952">(Jun 23 2021 at 17:11)</a>:</h4>
<p>Another performance neutral would be to patch lowering of special case of call to .len() on arrays to skip unsized cast into slice and directly generate Len in MIR, but this would be the most ugly I believe (well, modulo recent into_iter() changes, may be it’s acceptable)</p>



<a name="243684968"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243684968" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> scottmcm <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243684968">(Jun 23 2021 at 17:26)</a>:</h4>
<p>One potential way to look at <code>len</code> on arrays: if it's going to exist, <code>is_empty</code> should probably be added to arrays too.</p>
<p>(I don't know if that makes it more or less appetizing.  And I guess that <code>Vec</code> has <code>is_empty</code> even though it's never been strictly necessary.  Though passing <code>Vec::is_empty</code> as a function seems more plausible to me than passing <code>&lt;[i32; 7]&gt;::is_empty</code> as a function.)</p>



<a name="243684970"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243684970" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243684970">(Jun 23 2021 at 17:26)</a>:</h4>
<p>WRT to taking &amp;self, I think there's an argument that <code>.len()</code> is the single most pervasive "implicit interface" in std (i.e. a consistent idiom that isn't codified by a trait), and that it's reasonable for things to conform to that interface even if they don't need access to self. (Pre-1.0 <a href="https://internals.rust-lang.org/t/collection-traits-take-2/1272/15">there were designs for a <code>Collections</code> trait</a> (later abandoned due to lack of HKT), which likely would have included <code>fn len(&amp;self)</code>, which naturally people would have wanted to implement for arrays.) And since arrays are an important fundamental type, giving them their own implementation of this implicit interface feels like continuing the process of making arrays "first class" that was blocked for so long on const generics.</p>



<a name="243685665"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243685665" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bstrie <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243685665">(Jun 23 2021 at 17:31)</a>:</h4>
<p>I'm not going to argue too vehemently in favor, since after all we <em>don't</em> have any Collections interface and you'll always have <code>N</code> in scope anyway, so the utility is solely in the domain of "compiler optimizations which may or may not already exist or may or may not ever exist". But conceptually I think it would be natural, and impose no additional API surface area over what is currently exposed (and is potentially the smallest code addition in the history of std).</p>



<a name="243689102"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243689102" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243689102">(Jun 23 2021 at 17:57)</a>:</h4>
<p>Actually missed “is_empty()”, but agree that for consistency it should be added then</p>



<a name="243689251"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243689251" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243689251">(Jun 23 2021 at 17:58)</a>:</h4>
<p>Regarding the domain: I would not be surprised if people will write .len() and expect it to be optimized away by “powerful rust compiler” :)</p>



<a name="243694119"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243694119" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Lokathor <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243694119">(Jun 23 2021 at 18:33)</a>:</h4>
<p>I absolutely, positively, expect <code>len</code> to be optimized away, and cheaply.</p>



<a name="243694595"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243694595" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243694595">(Jun 23 2021 at 18:37)</a>:</h4>
<p>At the moment MIR const-prop runs before monomorphization, so it can only propagate concrete constants and not const generic N</p>



<a name="243694741"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243694741" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> cuviper <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243694741">(Jun 23 2021 at 18:38)</a>:</h4>
<p>needs some kind of symbolic const-prop?</p>



<a name="243698338"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243698338" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243698338">(Jun 23 2021 at 19:07)</a>:</h4>
<p>I think symbolic cost prop is a close relative of full const-generics and will require a larger work (my "new in rustc" point of view), but for purposes of bound checks elimination it should be ok to be able to reason that <code>_1 &lt; const N = true</code> by observing CFG</p>



<a name="243701244"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243701244" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243701244">(Jun 23 2021 at 19:33)</a>:</h4>
<p>any calls to <code>len()</code> will already be optimized out though?</p>



<a name="243701268"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243701268" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243701268">(Jun 23 2021 at 19:33)</a>:</h4>
<p>not by the default MIR opts but by LLVM's inliner</p>



<a name="243701332"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243701332" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243701332">(Jun 23 2021 at 19:34)</a>:</h4>
<p>though the MIR inliner should also handle it</p>



<a name="243702537"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243702537" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243702537">(Jun 23 2021 at 19:44)</a>:</h4>
<p>LLVM may do it because it runs after monomorphization, but it may be useful to be able to judge before it</p>



<a name="243719541"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243719541" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243719541">(Jun 23 2021 at 22:09)</a>:</h4>
<p>Thanks for the enlightening experiments and thorough analysis of all alternatives. I do believe that you are right, <em>in the future</em> this function may be the right way to go about it. But as noted, there is no immediate benefit, so we'd end up having very complex analyses that we need to maintain, or we have an additional function, that doesn't have much support for existing. So... do we really need the "eliminate duplicate bounds checks" optimization to work on arrays in order to show the benefit of that optimizations? Or are these actually orthogonal concerns? If it improves perf if used on slices, meaning a manual length check and an automatically inserted one (e.g. for an index op) do get deduplicated, then that is sufficient to get the pass merged. Arrays will get more prevalent with const generics, but they aren't as of yet, so focussing on arrays does not give us too much benefit I believe. I'd be happy to be proven otherwise with some perf results, but this is all very hard to actually do since we don't test runtime perf yet. So we're kind of stuck in a corner here, where we don't want to add complex MIR opts without compile-time benefits, but technically do want to extend our set of MIR opts to ones that improve runtime perf. Currently we trust in LLVM to take care of that, but if there are situations where that doesn't cut it, we should start by adding tests for that and then looking into improving them.</p>



<a name="243719761"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243719761" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243719761">(Jun 23 2021 at 22:12)</a>:</h4>
<p>I am fully aware I'm putting the entire burden on you by just stating this, but wg-mir-opt just doesn't have the capacity to do any major projects right now, so if you want to champion something in the direction of VRA, we will be happy to help design and figure out how to do it in a way that we can all be happy with. You won't be on your own, but we also won't just merge random mir opts that slightly improve the MIR without some perf or LLVM-ir tests that show that they improve things.</p>



<a name="243724713"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243724713" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243724713">(Jun 23 2021 at 23:15)</a>:</h4>
<p>I’ve initially wanted to do a VRA and had a simple prototype that would e.g. optimize a cast like “bool as u8”, but it’s most likely over the roof for me because ideally I then have to backpropagate the information to front end part and hint a users that some cases are reachable/unreachable. So then it transformed to an attempt to optimize away the famous bound checks, there are test examples in my PRs that should optimize the bound checks away in LLVM, but since LLVM is a black box and blocks with range checks and the following accesses are looking quite obvious in MIR I decided to go this way. So the current prototype tries to operate on a basis of logical relationships like “if we are in block bbX in CFG then we could only reach it from here, and in this case we have the following logical statements like _1 &lt; N, _2 = _1, so our statement Lt(_2, N) is always true and we can eliminate another terminator and just jump to the block of raw unsafe access by index”. This looks to work ok-ish and complexity is moderate, but for it I need more homogeneous MIR to start with, so slice::len were already patched into Len, now I’d want to preserve array length information for Len (otherwise in checks like “if i &lt; arr.len()” I get unsized cast + slice len, and in unsafe index access the comparison is between index and “const N”). Elimination of copies is useful in general and reduces the cost of trying to do such analysis because number of predicates reduced due to smaller numbers for copies and edges in a graph of relations. If I get all three prerequisites then there is a confidence that bound checks can be eliminated in MIR soundly and there will be less issues with “bound check is not eliminated”</p>



<a name="243724939"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243724939" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243724939">(Jun 23 2021 at 23:18)</a>:</h4>
<p>Regarding the concrete performance - is there any existing tooling for it? I believe that those MIR passes are strictly producing “better” MIR (more constants, less calls, etc), and if LLVM works worse after this (e.g. it can perform some optimizations after monomorphization when array length is done via unsized case + slice length instead of having it as a constant) then it’s a little separate issue with LLVM that has to be fixed anyway</p>



<a name="243728663"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243728663" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243728663">(Jun 24 2021 at 00:04)</a>:</h4>
<blockquote>
<p>it’s a little separate issue with LLVM that has to be fixed anyway</p>
</blockquote>
<p>yes, you are right, but we still can't decrease compile-time performance (especially for check and debug builds) and say "the regression is actually due to a different bug that we don't have a plan for fixing yet". There are issues like slightly different MIR causing huge perf regressions in LLVM that we have been unable to properly track down. Some are due to random choices with cgu splitting, others are simply causing some LLVM opt to run in circles</p>



<a name="243728917"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243728917" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243728917">(Jun 24 2021 at 00:08)</a>:</h4>
<blockquote>
<p>I believe that those MIR passes are strictly producing “better” MIR (more constants, less calls, etc)</p>
</blockquote>
<p>agreed, but if they cost performance at no measurable benefit, then that is an academic improvement. I do believe we will see actual improvements, just because it makes debug builds faster or rlibs smaller, but we don't have the infrastructure to track the latter. If nothing is improved by the mir opt except cleaner MIR, even with no compile time perf regression, should we add that mir opt? It is unclear to me, and wg-mir-opt has historically declined such new opts. We could change our stance here, but we need to discuss that separately from the specific opts here</p>



<a name="243728941"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243728941" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243728941">(Jun 24 2021 at 00:09)</a>:</h4>
<blockquote>
<p>Regarding the concrete performance - is there any existing tooling for it?</p>
</blockquote>
<p>There is the lolbench project, but I think it has stalled (somewhat?)</p>



<a name="243746909"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243746909" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243746909">(Jun 24 2021 at 06:42)</a>:</h4>
<p>I've sent a short reply to the GitHub PR thread about keccak. Another interesting fact is that keccak is a good demo of how current const prop can eliminate all the bound checks there and reduce them down to <code>assert(true)</code></p>



<a name="243747142"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/219381-t-libs/topic/Separate%20length%20function%20for%20arrays/near/243747142" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Alex Vlasov <a href="https://rust-lang.github.io/zulip_archive/stream/219381-t-libs/topic/Separate.20length.20function.20for.20arrays.html#243747142">(Jun 24 2021 at 06:46)</a>:</h4>
<p>Also keccak (one that is tested, not the round function in all it's varieties) doesn't have const generics, so MIR pass would not affect it anyway, and the library function also would not affect it - there are no .len() calls</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>